//
// Created by 86136 on 2024/11/22.
//
# pragma once
#include <cstdlib>
#include <cstring>
/*
 * 移植nginx内存池的代码，用OOP来实现
 */

// 类型重定义
using u_char = unsigned char;
using ngx_uint_t = unsigned int;

// 类型前置声明
struct ngx_pool_s;

// 清理函数的类型——回调函数
typedef void(*ngx_pool_cleanup_pt)(void *data);

// 以下结构体由ngx_pool_s.cleanup指向，也是存放在内存池的小块内存
struct ngx_pool_cleanup_s {
    ngx_pool_cleanup_pt  handler;   // 定义了一个函数指针，保存清理操作的回调函数
    void                 *data;     // 指向需要释放的资源
    ngx_pool_cleanup_s   *next;     // 释放资源的函数都放在一个链表，用next指向这个链表
};

/*
 * 大块内存的头部信息
 */
struct ngx_pool_large_s {
    ngx_pool_large_s    *next;
    void                *alloc;
};

/*
 * 分配小块内存池的头部数据信息
 */
struct ngx_pool_data_t {
    u_char      *last;  // 指向可用内存的起始地址
    u_char      *end;   // 指向可用内存的末尾地址
    ngx_pool_s  *next;  // 所有小块内存都串在一条链表上，该指针指向下一个内存块
    ngx_uint_t  failed; // 当前内存块分配空间失败的次数
};

/*
 * ngx内存池的头信息和管理成员信息
 */
struct ngx_pool_s {
    ngx_pool_data_t      d;         // 内存池块头信息
    size_t               max;       // 小块内存和大块内存的分界线
    ngx_pool_s           *current;  // 指向可用于分配空间的内存块（failed < 4）的起始地址
    ngx_pool_large_s     *large;    // 大块内存的入口指针
    ngx_pool_cleanup_s   *cleanup;  // 内存池块的清理操作，用户可设置回调函数，在内存池块释放之前执行清理操作
};

// buffer缓冲区清零
#define ngx_memzero(buf, n) (void)memset(buf, 0, n)
// 将开辟的内存调整到16的整数倍
#define ngx_align(d, a) (((d) + ((a) - 1)) & ~((a) - 1))
// 小块内存分配时考虑字节对齐的单位 平台一个字的大小
#define NGX_ALIGNMENT sizeof(unsigned long)
// 带有内存对齐的（把分配出去的起始地址对齐）小块内存池的分配，分配效率高，只做了指针的偏移
#define ngx_align_ptr(p, a) (u_char *) (((uintptr_t) (p) + ((uintptr_t) (a) - 1)) & ~((uintptr_t) (a) - 1))


// SGI STL小块和大块内存的分界点：128B
// nginx（给HTTP服务器所有的模块分配内存）小块和大块内存的分界点：4096B
const int ngx_pagesize = 4096;
// ngx小块内存池可分配的最大空间
const int NGX_MAX_ALLOC_FROM_POOL = ngx_pagesize - 1;
// 内存池默认大小 16k
const int NGX_DEFAULT_POOL_SIZE = 16 * 1024;

// 内存池字节按照16B对齐
const int NGX_POOL_ALIGNMENT = 16;
// ngx小块内存池最小的size调整为NGX_POOL_ALIGNMENT临近的倍数
const int NGX_MIN_POOL_SIZE = ngx_align((sizeof(ngx_pool_s) + 2 * sizeof(ngx_pool_large_s)), NGX_POOL_ALIGNMENT);

class ngx_mem_pool {
public:
    // 创建指定size大小的内存池，但小块内存池的大小不超过一个页面
    void *ngx_create_pool(size_t size);
    // 考虑内存字节对齐，从内存池申请size大小的内存
    void *ngx_palloc(size_t size);
    // 同上一个函数，但是不考虑内存字节对齐
    void *ngx_pnalloc(size_t size);
    // 同前一个函数，但是为内存初始化为0
    void *ngx_pcalloc(size_t size);
    // 释放大块内存
    void ngx_pfree(void *p);
    // 重置内存池
    void ngx_reset_pool();
    // 销毁内存池资源
    void ngx_destroy_pool();
    // 添加回调清理操作函数
    ngx_pool_cleanup_s *ngx_pool_cleanup_add(size_t size);
private:
    ngx_pool_s *pool;  // 指向ngx内存池的入口指针
    // 小块内存分配
    void *ngx_palloc_small(size_t size, ngx_uint_t align);
    // 大块内存分配
    void *ngx_palloc_large(size_t size);
    // 分配新的小块内存池
    void *ngx_palloc_block(size_t size);
};
